エンドポイントを使用してプライベートサブネットでECSを使用する
こんばんわ、札幌のヨシエです。
ECSは多方面のワークロードで使いやすい反面、クラスター内の情報通知やECRからコンテナイメージを取得するためにECS/ECRサービスへ接続する必要があることからインターネットへ接続できる必要があると考えておりました。
※既存のプライベートサブネットからS3などにアクセスするイメージです。
今回はPrivatelinkにてエンドポイントが用意されていたECS/ECRのエンドポイントを利用して、プライベートサブネットでECSを使用する方法を纏めてみます。
困っていたこと
上記で記載したようにPublicSubnetでECSクラスターを展開することに抵抗感がある事とNATGatewayを経由して接続するといったことをやりたくありませんでした。
結論
結果として、PrivateSubnetでECSを利用するためにはそれぞれのエンドポイントを作る必要がありました。
EC2とFargateのそれぞれで必要なエンドポイントは以下のようになりますので、参考になると嬉しいです。
ECSエンドポイント
エンドポイント名 | EC2 | Fargate |
---|---|---|
ecs-agent | 必要 | 不要 |
ecs-telemetry | 必要 | 不要 |
ecs | 必要 | 不要 |
ECRエンドポイント
エンドポイント名 | EC2 | Fargate |
---|---|---|
ecr.dkr | 必要 | 必要 |
ecr.api | 必要 | 不要 |
s3 | 必要 | 必要 |
logs | 使途によって追加 | 必要 |
構成説明
具体的なイメージとして2Tier(ALBとEC2を分離)構成を例として書いてみます。
この構成は採用されやすい構成でHTTP/HTTPS通信をALB経由でPrivateSubnetに配置されているEC2にリクエストが転送されます。
EC2はPrivateSubnetに配置されている点からインターネット経由でアクセスが出来ません。
上記のEC2構成をECSに置き換えてみます。
EC2がECSに置き換えられて、PublicSubnetにNATGatewayが追加配置しております。
これはコンテナスケーリングやコンテナイメージを取得するため、インターネットを経由して各サービス(ECS/ECR)へ接続する必要があるため必要になったNATGatewayです。
この構成で厳しいと考えられる点はNATGatewayがAZ障害等で利用不可となった際にECS/ECRへの通信が出来なくなる懸念がありました。
今回試した構成はNATGatewayを排除して、PrivateLinkを使用してECSとECRへ接続する方法を確認しました。
ECS/ECR VPCエンドポイントについて
ECS VPCエンドポイントについて
ECSを使用するためには3種類のVPCエンドポイントが必要となります。
各名称にておおよその推測はつくと思いますが、ECSクラスターのEC2で起動しているECS-Agentが通信をECSと通信を行うために使用されるエンドポイントと考えられます。
Fargateに関してはこちらのエンドポイントは不要となります、Fargate Onlyの環境ではコストが発生する観点からエンドポイントは作らない方針が良いと思われます。
- ecs-agent
- ecs-telemetry
- ecs
各エンドポイントの説明文章が見当たらないため、EC2(コンテナホスト)とエンドポイント(ENI)の通信制御を行うSecurityGroupを一時的に外すことで、想定どおりECS-Agentが通信できない状態に移行したことが確認できました。
ECR VPCエンドポイント
次にECRのVPCエンドポイントを整理してみます。
ECRはECSのコンテナホスト(EC2/Fargate)によって使用エンドポイントが異なりますので注意してください。
起動タイプに「EC2」を利用している時のエンドポイント
- ecr.dkr
- ECRへ
docker pull
やdocker push
を実行する時に利用されるエンドポイント
- ECRへ
- ecr.api
- ECRのAPIを呼び出すためのエンドポイント
- s3
- コンテナイメージを取得するためのエンドポイント
- ECRにはイメージのマニフェスト情報が配置されており、実際のコンテナレイヤー情報はS3に配置されている観点から必要
こちらも挙動を確認するためにテスト用のhttpdコンテナを起動しておき、起動中のコンテナとホストに保存されているコンテナイメージを削除します。
コンテナ状態
[root@ip-10-0-11-68 ~]# docker ps ; docker images CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 2462616cfeee xxxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/yoshie-httpd:latest "httpd-foreground" 54 seconds ago Up 53 seconds ecs-web-task-5-apache-8cadcc9e9481b1e83000 7612d4931cb1 amazon/amazon-ecs-pause:0.1.0 "./pause" 55 seconds ago Up 54 seconds ecs-web-task-5-internalecspause-c0b7d585b4e8fceee201 a57b9635ce59 amazon/amazon-ecs-agent:latest "/agent" 3 hours ago Up 3 hours (healthy) ecs-agent REPOSITORY TAG IMAGE ID CREATED SIZE amazon/amazon-ecs-agent latest 0d40082075b2 2 weeks ago 63.4MB amazon/amazon-ecs-pause 0.1.0 71cca41e8259 2 weeks ago 954kB xxxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/yoshie-httpd latest 96ba2182ff01 5 months ago 231MB
コンテナイメージ削除/コンテナ停止
[root@ip-10-0-11-68 ~]# docker rmi --force xxxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/yoshie-httpd ; docker kill 2462616cfeee Untagged: xxxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/yoshie-httpd:latest Untagged: xxxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/yoshie-httpd@sha256:4be2621192c24242d6c312c25c320eb898a754635ac0413dd229ea6005d8f27a 2462616cfeee
ECS-Agentがコンテナが終了したことを検知して、コンテナイメージから起動し直そうとしますがコンテナイメージも削除されているのでECRからイメージを取得します。
ECSエンドポイントと同じようにECR向けのセキュリティグループを一時的に外して挙動を確認しました。
ECS-Agentログ(コンテナ停止直後)
①コンテナの停止をECS-Agentが検知 2019-12-02T05:57:21Z [INFO] Managed task [arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxxx:task/8c0af069-2d07-490a-b3b2-8f7de87ee3ec]: sending container change event [apache]: arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxxx:task/8c0af069-2d07-490a-b3b2-8f7de87ee3ec apache -> STOPPED, Exit 137, , Known Sent: RUNNING ②docker pullに失敗 2019-12-02T06:02:28Z [WARN] DockerGoClient: failed to pull image xxxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/yoshie-httpd:latest: Error response from daemon: Get https://xxxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
上記のようにdocker pullが失敗していることがわかります。
セキュリティグループを再設定したところ以下の内容が出力されました。
2019-12-02T06:46:33Z [INFO] Task engine [arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxxx:task/a2bea75c-4d1c-4a7f-86fe-6d2d3b1ee56c]: pulling image xxxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/yoshie-httpd:latest for container apache concurrently 2019-12-02T06:46:33Z [INFO] Task engine [arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxxx:task/a2bea75c-4d1c-4a7f-86fe-6d2d3b1ee56c]: recording timestamp for starting image pulltime: 2019-12-02 06:46:33.632175896 +0000 UTC m=+15536.708536559 2019-12-02T06:46:33Z [INFO] Task engine [arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxxx:task/a2bea75c-4d1c-4a7f-86fe-6d2d3b1ee56c]: finished pulling image xxxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/yoshie-httpd:latest for container apache in 114.016015ms
起動タイプに「Fargate」を利用している時のエンドポイント
- ecr.dkr
- EC2と同様にdockerコマンドを実行するためのエンドポイント
- s3
- EC2と同様にコンテナイメージを取得するためのエンドポイント
- logs
- ログ情報をCloudWatchLogsへ送信するために必要なエンドポイント
- awslogs(CloudwatchLogs)を使用しないコンテナではエンドポイントは未作成で起動することが可能
- awslogsへログ出力されるタスク定義の場合、このエンドポイントが存在しないとタイムアウトで コンテナ起動が出来なくなる
Fargateではコンテナホストのログは見えない分、コンテナに関するログ出力はawslogsログドライバーを利用する形になるため構築時には注意した方が良さそうです。
最後に
ECS/ECRのエンドポイントについてようやく整理が出来ました。
今回特に気にしたのはECRで利用されるCloudWatchLogsへのログ転送用エンドポイントlogs
とコンテナイメージ取得用エンドポイントのS3
がなぜ必要なのかが整理出来たことはポイントとして大きいです。
ウェブサーバーの例で今回は書きましたが、外部に晒したくない処理を行わせるためにもコンテナは非常に重宝されるのでぜひお試し頂ければと思います。